home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / WINGs / wfilepanel.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-03-28  |  27.2 KB  |  1,011 lines

  1.  
  2. #include "WINGsP.h"
  3.  
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <unistd.h>
  7. #include <dirent.h>
  8. #include <limits.h>
  9. #include <errno.h>
  10.  
  11. #ifndef PATH_MAX
  12. #define PATH_MAX 1024
  13. #endif
  14.  
  15. #ifndef FLOPPY_PATH
  16. #define FLOPPY_PATH "/floppy"
  17. #endif
  18.  
  19. typedef struct W_FilePanel {
  20.     WMWindow *win;
  21.     
  22.     WMLabel *iconLabel;
  23.     WMLabel *titleLabel;
  24.     
  25.     WMFrame *line;
  26.  
  27.     WMLabel *nameLabel;
  28.     WMBrowser *browser;
  29.     
  30.     WMButton *okButton;
  31.     WMButton *cancelButton;
  32.     
  33.     WMButton *homeButton;
  34.     WMButton *trashcanButton;
  35.     WMButton *createDirButton;
  36.     WMButton *disketteButton;
  37.     WMButton *unmountButton;
  38.  
  39.     WMView *accessoryView;
  40.  
  41.     WMTextField *fileField;
  42.     
  43.     char **fileTypes;
  44.  
  45.     struct {
  46.     unsigned int canExit:1;
  47.     unsigned int canceled:1;       /* clicked on cancel */
  48.     unsigned int done:1;
  49.     unsigned int filtered:1;
  50.     unsigned int canChooseFiles:1;
  51.     unsigned int canChooseDirectories:1;
  52.     unsigned int autoCompletion:1;
  53.     unsigned int showAllFiles:1;
  54.     unsigned int canFreeFileTypes:1;
  55.     unsigned int fileMustExist:1;
  56.     unsigned int panelType:1;
  57.     } flags;
  58. } W_FilePanel;
  59.  
  60.  
  61. /* Type of panel */
  62. #define WP_OPEN         0
  63. #define WP_SAVE         1
  64.  
  65. #define PWIDTH        330
  66. #define PHEIGHT     360
  67.  
  68. static void listDirectoryOnColumn(WMFilePanel *panel, int column, char *path);
  69. static void browserClick();
  70. static void browserDClick();
  71.  
  72. static void fillColumn(WMBrowserDelegate *self, WMBrowser *bPtr, int column,
  73.                WMList *list);
  74.  
  75. static void deleteFile();
  76.  
  77. static void createDir();
  78.  
  79. static void goHome();
  80.  
  81. static void goFloppy();
  82.  
  83. static void goUnmount();
  84.  
  85. static void buttonClick();
  86.  
  87. static char *getCurrentFileName(WMFilePanel *panel);
  88.  
  89. static void handleEvents(XEvent *event, void *data);
  90.  
  91.  
  92.  
  93. static WMBrowserDelegate browserDelegate = {
  94.     NULL, /* data */
  95.     fillColumn, /* createRowsForColumn */
  96.     NULL, /* titleOfColumn */
  97.     NULL, /* didScroll */
  98.     NULL  /* willScroll */
  99. };
  100.  
  101.  
  102. static int
  103. closestListItem(WMList *list, char *text, Bool exact)
  104. {
  105.     WMListItem *item;
  106.     WMBag *items = WMGetListItems(list);
  107.     WMBagIterator i;
  108.     int len = strlen(text);
  109.  
  110.     if (len==0)
  111.     return -1;
  112.  
  113.     WM_ITERATE_BAG(items, item, i) {
  114.         if (strlen(item->text) >= len &&
  115.             ((exact && strcmp(item->text, text)==0) ||
  116.              (!exact && strncmp(item->text, text, len)==0))) {
  117.         return WMBagIndexForIterator(items, i);
  118.     }
  119.     }
  120.  
  121.     return -1;
  122. }
  123.  
  124.  
  125. static void
  126. textChangedObserver(void *observerData, WMNotification *notification)
  127. {
  128.     W_FilePanel *panel = (W_FilePanel*)observerData;
  129.     char *text;
  130.     WMList *list;
  131.     int col = WMGetBrowserNumberOfColumns(panel->browser) - 1;
  132.     int i, textEvent;
  133.  
  134.     if (!(list = WMGetBrowserListInColumn(panel->browser, col)))
  135.     return;
  136.  
  137.     text = WMGetTextFieldText(panel->fileField);
  138.     textEvent = (int)WMGetNotificationClientData(notification);
  139.  
  140.     if (panel->flags.autoCompletion && textEvent!=WMDeleteTextEvent)
  141.         i = closestListItem(list, text, False);
  142.     else
  143.         i = closestListItem(list, text, True);
  144.  
  145.     WMSelectListItem(list, i);
  146.     if (i>=0 && panel->flags.autoCompletion) {
  147.         WMListItem *item = WMGetListItem(list, i);
  148.         int textLen = strlen(text), itemTextLen = strlen(item->text);
  149.         int visibleItems = WMWidgetHeight(list)/WMGetListItemHeight(list);
  150.     
  151.         WMSetListPosition(list, i - visibleItems/2);
  152.     
  153.         if (textEvent!=WMDeleteTextEvent) {
  154.             WMRange range;
  155.  
  156.         WMInsertTextFieldText(panel->fileField, &item->text[textLen],
  157.                                   textLen);
  158.         range.position = textLen;
  159.         range.count = itemTextLen - textLen;
  160.         WMSelectTextFieldRange(panel->fileField, range);
  161.             /*WMSetTextFieldCursorPosition(panel->fileField, itemTextLen);*/
  162.     }
  163.     }
  164.  
  165.     wfree(text);
  166. }
  167.  
  168.  
  169. static void
  170. textEditedObserver(void *observerData, WMNotification *notification)
  171. {
  172.     W_FilePanel *panel = (W_FilePanel*)observerData;
  173.  
  174.     if ((int)WMGetNotificationClientData(notification)==WMReturnTextMovement) {
  175.     WMPerformButtonClick(panel->okButton);
  176.     }
  177. }
  178.  
  179.  
  180.  
  181. static WMFilePanel*
  182. makeFilePanel(WMScreen *scrPtr, char *name, char *title)
  183. {
  184.     WMFilePanel *fPtr;
  185.     WMFont *largeFont;
  186.     
  187.     fPtr = wmalloc(sizeof(WMFilePanel));
  188.     memset(fPtr, 0, sizeof(WMFilePanel));
  189.  
  190.     fPtr->win = WMCreateWindowWithStyle(scrPtr, name, WMTitledWindowMask
  191.                     |WMResizableWindowMask);
  192.     WMResizeWidget(fPtr->win, PWIDTH, PHEIGHT);
  193.     WMSetWindowTitle(fPtr->win, "");
  194.  
  195.     WMCreateEventHandler(WMWidgetView(fPtr->win), StructureNotifyMask,
  196.                          handleEvents, fPtr);
  197.     WMSetWindowMinSize(fPtr->win, PWIDTH, PHEIGHT);
  198.  
  199.  
  200.     fPtr->iconLabel = WMCreateLabel(fPtr->win);
  201.     WMResizeWidget(fPtr->iconLabel, 64, 64);
  202.     WMMoveWidget(fPtr->iconLabel, 0, 0);
  203.     WMSetLabelImagePosition(fPtr->iconLabel, WIPImageOnly);
  204.     WMSetLabelImage(fPtr->iconLabel, scrPtr->applicationIcon);
  205.     
  206.     fPtr->titleLabel = WMCreateLabel(fPtr->win);
  207.     WMResizeWidget(fPtr->titleLabel, PWIDTH-64, 64);
  208.     WMMoveWidget(fPtr->titleLabel, 64, 0);
  209.     largeFont = WMBoldSystemFontOfSize(scrPtr, 24);
  210.     WMSetLabelFont(fPtr->titleLabel, largeFont);
  211.     WMReleaseFont(largeFont);
  212.     WMSetLabelText(fPtr->titleLabel, title);
  213.     
  214.     fPtr->line = WMCreateFrame(fPtr->win);
  215.     WMMoveWidget(fPtr->line, 0, 64);
  216.     WMResizeWidget(fPtr->line, PWIDTH, 2);
  217.     WMSetFrameRelief(fPtr->line, WRGroove);
  218.  
  219.     fPtr->browser = WMCreateBrowser(fPtr->win);
  220.     WMSetBrowserDelegate(fPtr->browser, &browserDelegate);
  221.     WMSetBrowserAction(fPtr->browser, browserClick, fPtr);
  222.     WMSetBrowserDoubleAction(fPtr->browser, browserDClick, fPtr);
  223.     WMMoveWidget(fPtr->browser, 7, 72);
  224.     WMResizeWidget(fPtr->browser, PWIDTH-14,200);
  225.     WMHangData(fPtr->browser, fPtr);
  226.  
  227.     fPtr->nameLabel = WMCreateLabel(fPtr->win);
  228.     WMMoveWidget(fPtr->nameLabel, 7, 282);
  229.     WMResizeWidget(fPtr->nameLabel, 55, 14);
  230.     WMSetLabelText(fPtr->nameLabel, "Name:");
  231.     
  232.     fPtr->fileField = WMCreateTextField(fPtr->win);
  233.     WMMoveWidget(fPtr->fileField, 60, 278);
  234.     WMResizeWidget(fPtr->fileField, PWIDTH-60-10, 24);
  235.     WMAddNotificationObserver(textEditedObserver, fPtr,
  236.                   WMTextDidEndEditingNotification,
  237.                   fPtr->fileField);
  238.     WMAddNotificationObserver(textChangedObserver, fPtr,
  239.                   WMTextDidChangeNotification,
  240.                   fPtr->fileField);
  241.     
  242.     fPtr->okButton = WMCreateCommandButton(fPtr->win);
  243.     WMMoveWidget(fPtr->okButton, 245, 325);
  244.     WMResizeWidget(fPtr->okButton, 75, 28);
  245.     WMSetButtonText(fPtr->okButton, "OK");
  246.     WMSetButtonImage(fPtr->okButton, scrPtr->buttonArrow);
  247.     WMSetButtonAltImage(fPtr->okButton, scrPtr->pushedButtonArrow);
  248.     WMSetButtonImagePosition(fPtr->okButton, WIPRight);
  249.     WMSetButtonAction(fPtr->okButton, buttonClick, fPtr);
  250.     
  251.     fPtr->cancelButton = WMCreateCommandButton(fPtr->win);
  252.     WMMoveWidget(fPtr->cancelButton, 165, 325);
  253.     WMResizeWidget(fPtr->cancelButton, 75, 28);
  254.     WMSetButtonText(fPtr->cancelButton, "Cancel");
  255.     WMSetButtonAction(fPtr->cancelButton, buttonClick, fPtr);
  256.  
  257.     fPtr->trashcanButton = WMCreateCommandButton(fPtr->win);
  258.     WMMoveWidget(fPtr->trashcanButton, 7, 325);
  259.     WMResizeWidget(fPtr->trashcanButton, 28, 28);
  260.     WMSetButtonImagePosition(fPtr->trashcanButton, WIPImageOnly);
  261.     WMSetButtonImage(fPtr->trashcanButton, scrPtr->trashcanIcon);
  262.     WMSetButtonAltImage(fPtr->trashcanButton, scrPtr->altTrashcanIcon);
  263.     WMSetButtonAction(fPtr->trashcanButton, deleteFile, fPtr);
  264.  
  265.     fPtr->createDirButton = WMCreateCommandButton(fPtr->win);
  266.     WMMoveWidget(fPtr->createDirButton, 37, 325);
  267.     WMResizeWidget(fPtr->createDirButton, 28, 28);
  268.     WMSetButtonImagePosition(fPtr->createDirButton, WIPImageOnly);
  269.     WMSetButtonImage(fPtr->createDirButton, scrPtr->createDirIcon);
  270.     WMSetButtonAltImage(fPtr->createDirButton, scrPtr->altCreateDirIcon);
  271.     WMSetButtonAction(fPtr->createDirButton, createDir, fPtr);
  272.  
  273.     fPtr->homeButton = WMCreateCommandButton(fPtr->win);
  274.     WMMoveWidget(fPtr->homeButton, 67, 325);
  275.     WMResizeWidget(fPtr->homeButton, 28, 28);
  276.     WMSetButtonImagePosition(fPtr->homeButton, WIPImageOnly);
  277.     WMSetButtonImage(fPtr->homeButton, scrPtr->homeIcon);
  278.     WMSetButtonAltImage(fPtr->homeButton, scrPtr->altHomeIcon);
  279.     WMSetButtonAction(fPtr->homeButton, goHome, fPtr);
  280.  
  281.     fPtr->disketteButton = WMCreateCommandButton(fPtr->win);
  282.     WMMoveWidget(fPtr->disketteButton, 97, 325);
  283.     WMResizeWidget(fPtr->disketteButton, 28, 28);
  284.     WMSetButtonImagePosition(fPtr->disketteButton, WIPImageOnly);
  285.     WMSetButtonImage(fPtr->disketteButton, scrPtr->disketteIcon);
  286.     WMSetButtonAltImage(fPtr->disketteButton, scrPtr->altDisketteIcon);
  287.     WMSetButtonAction(fPtr->disketteButton, goFloppy, fPtr);
  288.  
  289.     fPtr->unmountButton = WMCreateCommandButton(fPtr->win);
  290.     WMMoveWidget(fPtr->unmountButton, 127, 325);
  291.     WMResizeWidget(fPtr->unmountButton, 28, 28);
  292.     WMSetButtonImagePosition(fPtr->unmountButton, WIPImageOnly);
  293.     WMSetButtonImage(fPtr->unmountButton, scrPtr->unmountIcon);
  294.     WMSetButtonAltImage(fPtr->unmountButton, scrPtr->altUnmountIcon);
  295.     WMSetButtonAction(fPtr->unmountButton, goUnmount, fPtr);
  296.     WMSetButtonEnabled(fPtr->unmountButton, False);
  297.  
  298.  
  299.     WMRealizeWidget(fPtr->win);
  300.     WMMapSubwidgets(fPtr->win);
  301.  
  302.     WMSetFocusToWidget(fPtr->fileField);
  303.     WMSetTextFieldCursorPosition(fPtr->fileField, 0);
  304.  
  305.     WMLoadBrowserColumnZero(fPtr->browser);
  306.     
  307.     WMSetWindowInitialPosition(fPtr->win,
  308.            (scrPtr->rootView->size.width - WMWidgetWidth(fPtr->win))/2,
  309.                (scrPtr->rootView->size.height - WMWidgetHeight(fPtr->win))/2);
  310.  
  311.     fPtr->flags.canChooseFiles = 1;
  312.     fPtr->flags.canChooseDirectories = 1;
  313.     fPtr->flags.autoCompletion = 1;
  314.  
  315.     return fPtr;
  316. }
  317.  
  318.  
  319. WMOpenPanel*
  320. WMGetOpenPanel(WMScreen *scrPtr)
  321. {
  322.     WMFilePanel *panel;
  323.     
  324.     if (scrPtr->sharedOpenPanel)
  325.     return scrPtr->sharedOpenPanel;
  326.  
  327.     panel = makeFilePanel(scrPtr, "openFilePanel", "Open");
  328.     panel->flags.fileMustExist = 1;
  329.     panel->flags.panelType = WP_OPEN;
  330.  
  331.     scrPtr->sharedOpenPanel = panel;
  332.  
  333.     return panel;
  334. }
  335.  
  336.  
  337. WMSavePanel*
  338. WMGetSavePanel(WMScreen *scrPtr)
  339. {
  340.     WMFilePanel *panel;
  341.  
  342.     if (scrPtr->sharedSavePanel)
  343.     return scrPtr->sharedSavePanel;
  344.  
  345.     panel = makeFilePanel(scrPtr, "saveFilePanel", "Save");
  346.     panel->flags.fileMustExist = 0;
  347.     panel->flags.panelType = WP_SAVE;
  348.  
  349.     scrPtr->sharedSavePanel = panel;
  350.  
  351.     return panel;
  352. }
  353.  
  354.  
  355. void
  356. WMFreeFilePanel(WMFilePanel *panel)
  357. {
  358.     if (panel == WMWidgetScreen(panel->win)->sharedSavePanel) {
  359.     WMWidgetScreen(panel->win)->sharedSavePanel = NULL;
  360.     }
  361.     if (panel == WMWidgetScreen(panel->win)->sharedOpenPanel) {
  362.     WMWidgetScreen(panel->win)->sharedOpenPanel = NULL;
  363.     }
  364.     WMRemoveNotificationObserver(panel);
  365.     WMUnmapWidget(panel->win);
  366.     WMDestroyWidget(panel->win);
  367.     wfree(panel);
  368. }
  369.  
  370.  
  371. int
  372. WMRunModalFilePanelForDirectory(WMFilePanel *panel, WMWindow *owner,
  373.                                 char *path, char *name, char **fileTypes)
  374. {
  375.     WMScreen *scr = WMWidgetScreen(panel->win);
  376.     XEvent event;
  377.  
  378.     if (name && !owner) {
  379.         WMSetWindowTitle(panel->win, name);
  380.     }
  381.  
  382.     WMChangePanelOwner(panel->win, owner);
  383.  
  384.     WMSetFilePanelDirectory(panel, path);
  385.  
  386.     panel->flags.done = 0;
  387.     switch(panel->flags.panelType) {
  388.     case WP_OPEN:
  389.         if (fileTypes)
  390.             panel->flags.filtered = 1;
  391.         panel->fileTypes = fileTypes;
  392.         if (name == NULL)
  393.             name = "Open";
  394.         break;
  395.     case WP_SAVE:
  396.         panel->fileTypes = NULL;
  397.         panel->flags.filtered = 0;
  398.         if (name == NULL)
  399.             name = "Save";
  400.         break;
  401.     default:
  402.         break;
  403.     }
  404.  
  405.     WMSetLabelText(panel->titleLabel, name);
  406.  
  407.     scr->modalView = W_VIEW(panel->win);
  408.     WMMapWidget(panel->win);
  409.  
  410.     scr->modal = 1;
  411.     while (!panel->flags.done) {    
  412.     WMNextEvent(scr->display, &event);
  413.     WMHandleEvent(&event);
  414.     }
  415.     scr->modal = 0;
  416.  
  417.     /* Must withdraw window because the next time we map
  418.      * it, it might have a different transient owner. 
  419.      */
  420.     WMCloseWindow(panel->win);
  421.  
  422.     return (panel->flags.canceled ? False : True);
  423. }
  424.  
  425.  
  426.  
  427.  
  428. void
  429. WMSetFilePanelDirectory(WMFilePanel *panel, char *path)
  430. {
  431.     WMList *list;
  432.     WMListItem *item;
  433.     int col;
  434.     char *rest;
  435.  
  436.     rest = WMSetBrowserPath(panel->browser, path);
  437.     if (strcmp(path, "/")==0)
  438.         rest = NULL;
  439.  
  440.     col = WMGetBrowserSelectedColumn(panel->browser);
  441.     list = WMGetBrowserListInColumn(panel->browser, col);
  442.     if (list && (item = WMGetListSelectedItem(list))) {
  443.         if (item->isBranch) {
  444.             WMSetTextFieldText(panel->fileField, rest);
  445.         } else {
  446.             WMSetTextFieldText(panel->fileField, item->text);
  447.         }
  448.     } else {
  449.         WMSetTextFieldText(panel->fileField, rest);
  450.     }
  451. }
  452.  
  453.             
  454. void
  455. WMSetFilePanelCanChooseDirectories(WMFilePanel *panel, Bool flag)
  456. {
  457.     panel->flags.canChooseDirectories = flag;
  458. }
  459.  
  460. void
  461. WMSetFilePanelCanChooseFiles(WMFilePanel *panel, Bool flag)
  462. {
  463.     panel->flags.canChooseFiles = flag;
  464. }
  465.  
  466.  
  467. void
  468. WMSetFilePanelAutoCompletion(WMFilePanel *panel, Bool flag)
  469. {
  470.     panel->flags.autoCompletion = flag;
  471. }
  472.  
  473.  
  474. char*
  475. WMGetFilePanelFileName(WMFilePanel *panel)
  476. {
  477.     return getCurrentFileName(panel);
  478. }
  479.  
  480.  
  481. void
  482. WMSetFilePanelAccessoryView(WMFilePanel *panel, WMView *view)
  483. {
  484.     WMView *v;
  485.  
  486.     panel->accessoryView = view;
  487.  
  488.     v = WMWidgetView(panel->win);
  489.  
  490.     W_ReparentView(view, v, 0, 0);
  491.  
  492.     W_MoveView(view, (v->size.width - v->size.width)/2, 300);
  493. }
  494.  
  495.  
  496. WMView*
  497. WMGetFilePanelAccessoryView(WMFilePanel *panel)
  498. {
  499.     return panel->accessoryView;
  500. }
  501.  
  502.  
  503. static char*
  504. get_name_from_path(char *path)
  505. {
  506.     int size;
  507.     
  508.     assert(path!=NULL);
  509.         
  510.     size = strlen(path);
  511.  
  512.     /* remove trailing / */
  513.     while (size > 0 && path[size-1]=='/')
  514.     size--;
  515.     /* directory was root */
  516.     if (size == 0)
  517.     return wstrdup("/");
  518.  
  519.     while (size > 0 && path[size-1] != '/')
  520.     size--;
  521.     
  522.     return wstrdup(&(path[size]));
  523. }
  524.  
  525.  
  526. static int
  527. filterFileName(WMFilePanel *panel, char *file, Bool isDirectory)
  528. {
  529.     return True;
  530. }
  531.  
  532.  
  533. #define CAST(item) (*((WMListItem**)item))
  534. static int
  535. comparer(const void *a, const void *b)
  536. {
  537.     if (CAST(a)->isBranch == CAST(b)->isBranch)
  538.       return (strcmp(CAST(a)->text, CAST(b)->text));
  539.     if (CAST(a)->isBranch)
  540.       return (-1);
  541.     return (1);
  542. }
  543. #undef CAST
  544.  
  545.  
  546. static void
  547. listDirectoryOnColumn(WMFilePanel *panel, int column, char *path)
  548. {
  549.     WMBrowser *bPtr = panel->browser;
  550.     struct dirent *dentry;
  551.     DIR *dir;
  552.     struct stat stat_buf;
  553.     char pbuf[PATH_MAX+16];
  554.  
  555.     assert(column >= 0);
  556.     assert(path != NULL);
  557.  
  558.     /* put directory name in the title */
  559.     WMSetBrowserColumnTitle(bPtr, column, get_name_from_path(path));
  560.     
  561.     dir = opendir(path);
  562.     
  563.     if (!dir) {
  564. #ifdef VERBOSE
  565.     printf("WINGs: could not open directory %s\n", path);
  566. #endif
  567.     return;
  568.     }
  569.  
  570.     /* list contents in the column */
  571.     while ((dentry = readdir(dir))) {           
  572.     if (strcmp(dentry->d_name, ".")==0 ||
  573.         strcmp(dentry->d_name, "..")==0)
  574.         continue;
  575.  
  576.     strcpy(pbuf, path);
  577.     if (strcmp(path, "/")!=0)
  578.         strcat(pbuf, "/");
  579.     strcat(pbuf, dentry->d_name);
  580.  
  581.     if (stat(pbuf, &stat_buf)!=0) {
  582. #ifdef VERBOSE
  583.         printf("WINGs: could not stat %s\n", pbuf);
  584. #endif
  585.         continue;
  586.     } else {
  587.         int isDirectory;
  588.  
  589.         isDirectory = S_ISDIR(stat_buf.st_mode);
  590.         
  591.         if (filterFileName(panel, dentry->d_name, isDirectory))
  592.         WMInsertBrowserItem(bPtr, column, -1, dentry->d_name, isDirectory);
  593.     }
  594.     }
  595.     WMSortBrowserColumnWithComparer(bPtr, column, comparer);
  596.  
  597.     closedir(dir);
  598. }
  599.  
  600.  
  601. static void
  602. fillColumn(WMBrowserDelegate *self, WMBrowser *bPtr, int column, WMList *list)
  603. {
  604.     char *path;
  605.     WMFilePanel *panel;
  606.     
  607.     if (column > 0) {
  608.     path = WMGetBrowserPathToColumn(bPtr, column-1);
  609.     } else {
  610.     path = wstrdup("/");
  611.     }
  612.  
  613.     panel = WMGetHangedData(bPtr);
  614.     listDirectoryOnColumn(panel, column, path);
  615.     wfree(path);
  616. }
  617.  
  618.  
  619. static void 
  620. browserDClick(WMBrowser *bPtr, WMFilePanel *panel)
  621. {
  622.     WMPerformButtonClick(panel->okButton);
  623. }
  624.  
  625. static void 
  626. browserClick(WMBrowser *bPtr, WMFilePanel *panel)
  627. {
  628.     int col = WMGetBrowserSelectedColumn(bPtr);
  629.     WMListItem *item = WMGetBrowserSelectedItemInColumn(bPtr, col);
  630.  
  631.     if (!item || item->isBranch)
  632.     WMSetTextFieldText(panel->fileField, NULL);
  633.     else {
  634.     WMSetTextFieldText(panel->fileField, item->text);
  635.     }
  636. }
  637.  
  638.  
  639. static void
  640. showError(WMScreen *scr, WMWindow *owner, char *s, char *file)
  641. {
  642.     char *errStr;
  643.  
  644.     if (file) {
  645.         errStr = wmalloc(strlen(file)+strlen(s));
  646.         sprintf(errStr, s, file);
  647.     } else {
  648.         errStr = wstrdup(s);
  649.     }
  650.     WMRunAlertPanel(scr, owner, "Error", errStr, "OK", NULL, NULL);
  651.     wfree(errStr);
  652. }
  653.  
  654.  
  655. static void
  656. createDir(WMButton *bPre, WMFilePanel *panel)
  657. {
  658.     char *directory_name;
  659.     char *directory;
  660.     char *file;
  661.     char *s;
  662.     WMScreen *scr = WMWidgetScreen(panel->win);
  663.     WMInputPanel *_panel;
  664.  
  665.     _panel = WMCreateInputPanel(scr, panel->win,
  666.             "Create Directory", "Enter directory name", "", "OK", "Cancel");
  667.     scr->modalView = W_VIEW(_panel->win);
  668.     WMMapWidget(_panel->win);
  669.     scr->modal = 1;
  670.     while (!_panel->done || WMScreenPending(scr)) {
  671.         XEvent event;
  672.         WMNextEvent(scr->display, &event);
  673.         WMHandleEvent(&event);
  674.     }
  675.     scr->modal = 0;
  676.  
  677.     if (_panel->result == WAPRDefault)
  678.         directory_name = WMGetTextFieldText(_panel->text);
  679.     else {
  680.         WMDestroyInputPanel(_panel);
  681.         return;
  682.     }
  683.  
  684.     WMDestroyInputPanel(_panel);
  685.  
  686.     directory = getCurrentFileName(panel);
  687.     {
  688.         char *s = strrchr(directory,'/');
  689.         if (s) s[1] = 0;
  690.     }
  691.  
  692.     if (directory_name[0] == '/') {
  693.         directory[0] = 0;
  694.     } else {
  695.         while ((s = strstr(directory,"//"))) {
  696.             int i;
  697.             for (i = 2;s[i] == '/';i++);
  698.             strcpy(s, &s[i-1]);
  699.         }
  700.         if ((s = strrchr(directory, '/')) && !s[1]) s[0] = 0;
  701.     }
  702.     while ((s = strstr(directory_name,"//"))) {
  703.         int i;
  704.         for (i = 2;s[i] == '/';i++);
  705.         strcpy(s, &s[i-1]);
  706.     }
  707.     if ((s = strrchr(directory_name, '/')) && !s[1]) s[0] = 0;
  708.  
  709.     file = wmalloc(strlen(directory_name)+strlen(directory)+1);
  710.     sprintf(file, "%s/%s", directory, directory_name);
  711.     while ((s = strstr(file,"//"))) {
  712.         int i;
  713.         for (i = 2;s[i] == '/';i++);
  714.         strcpy(s, &s[i-1]);
  715.     }
  716.  
  717.     if (mkdir(file,0xfff) != 0) {
  718.         switch (errno) {
  719.             case EACCES:
  720.                 showError(scr, panel->win, "Permission denied.", NULL);
  721.                 break;
  722.             case EEXIST:
  723.                 showError(scr, panel->win, "'%s' already existes.", file);
  724.                 break;
  725.             case ENOENT:
  726.                 showError(scr, panel->win, "Path does not exist.", NULL);
  727.         }
  728.     }
  729.     else WMSetFilePanelDirectory(panel, file);
  730.  
  731.     wfree(directory_name);
  732.     wfree(directory);
  733.     wfree(file);
  734.  
  735. }
  736.  
  737. static void
  738. deleteFile(WMButton *bPre, WMFilePanel *panel)
  739. {
  740.     char *file;
  741.     char *buffer, *s;
  742.     struct stat filestat;
  743.     WMScreen *scr = WMWidgetScreen(panel->win);
  744.  
  745.     file = getCurrentFileName(panel);
  746.  
  747.     while ((s = strstr(file,"//"))) {
  748.         int i;
  749.         for (i = 2;s[i] == '/';i++);
  750.         strcpy(s, &s[i-1]);
  751.     }
  752.     if (strlen(file) > 1 && (s = strrchr(file, '/')) && !s[1]) s[0] = 0;
  753.  
  754.     if (stat(file,&filestat)) {
  755.         switch (errno) {
  756.             case ENOENT:
  757.                 showError(scr, panel->win, "'%s' does not exist.", file);
  758.                 break;
  759.             case EACCES:
  760.                 showError(scr, panel->win, "Permission denied.", NULL);
  761.                 break;
  762.             case ENOMEM:
  763.                 showError(scr, panel->win,
  764.                         "Insufficient memory available.", NULL);
  765.                 break;
  766.             case EROFS:
  767.                 showError(scr, panel->win,
  768.                         "'%s' is on a read-only filesystem.", file);
  769.                 break;
  770.             default:
  771.                 showError(scr, panel->win, "Can not delete '%s'.", file);
  772.         }
  773.         wfree(file);
  774.         return;
  775.     } else if (S_ISDIR(filestat.st_mode)) {
  776.         buffer = wmalloc(strlen(file)+20);
  777.         sprintf(buffer,"Delete directory %s ?",file);
  778.     } else {
  779.         buffer = wmalloc(strlen(file)+15);
  780.         sprintf(buffer,"Delete file %s ?",file);
  781.     }
  782.  
  783.     if (!WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
  784.                 "Warning", buffer, "OK", "Cancel", NULL)) {
  785.         if (S_ISDIR(filestat.st_mode)) {
  786.             if (rmdir(file) != 0) {
  787.                 switch (errno) {
  788.                     case EACCES:
  789.                         showError(scr, panel->win, "Permission denied.", NULL);
  790.                         break;
  791.                     case ENOENT:
  792.                         showError(scr, panel->win, "Directory '%s' does not exist.", file);
  793.                         break;
  794.                     case ENOTEMPTY:
  795.                         showError(scr, panel->win, "Directory '%s' is not empty.", file);
  796.                         break;
  797.                     case EBUSY:
  798.                         showError(scr, panel->win, "Directory '%s' is busy.", file);
  799.                         break;
  800.                     default:
  801.                         showError(scr, panel->win, "Can not delete '%s'.", file);
  802.                 }
  803.             } else {
  804.                 char *s = strrchr(file,'/');
  805.                 if (s) s[0] = 0;
  806.                 WMSetFilePanelDirectory(panel, file);
  807.             }
  808.         } else if (remove(file) != 0) {
  809.             switch (errno) {
  810.                 case EISDIR:
  811.                     showError(scr, panel->win, "'%s' is a directory.", file);
  812.                     break;
  813.                 case ENOENT:
  814.                     showError(scr, panel->win, "'%s' does not exist.", file);
  815.                     break;
  816.                 case EACCES:
  817.                     showError(scr, panel->win, "Permission denied.", NULL);
  818.                     break;
  819.                 case ENOMEM:
  820.                     showError(scr, panel->win,
  821.                             "Insufficient memory available.", NULL);
  822.                     break;
  823.                 case EROFS:
  824.                     showError(scr, panel->win,
  825.                             "'%s' is on a read-only filesystem.", file);
  826.                     break;
  827.                 default:
  828.                     showError(scr, panel->win, "Can not delete '%s'.", file);
  829.             }
  830.         } else {
  831.             char *s = strrchr(file,'/');
  832.             if (s) s[1] = 0;
  833.             WMSetFilePanelDirectory(panel, file);
  834.         }
  835.     }
  836.     wfree(buffer);
  837.     wfree(file);
  838. }
  839.  
  840. static void
  841. goUnmount(WMButton *bPtr, WMFilePanel *panel)
  842. {
  843. }
  844.  
  845.  
  846. static void
  847. goFloppy(WMButton *bPtr, WMFilePanel *panel)
  848. {
  849.     char *file;
  850.     struct stat filestat;
  851.     WMScreen *scr = WMWidgetScreen(panel->win);
  852.  
  853.     file = FLOPPY_PATH;
  854.     if (stat(FLOPPY_PATH,&filestat)) {
  855.         showError(scr, panel->win, "An error occured browsing '%s'.", file);
  856.         return;
  857.     } else if (!S_ISDIR(filestat.st_mode)) {
  858.         showError(scr, panel->win, "'%s' is not a directory.", file);
  859.         return;
  860.     }
  861.     
  862.     WMSetFilePanelDirectory(panel, FLOPPY_PATH);
  863. }
  864.  
  865.  
  866. static void
  867. goHome(WMButton *bPtr, WMFilePanel *panel)
  868. {
  869.     char *home;
  870.  
  871.     /* home is statically allocated. Don't free it! */
  872.     home = wgethomedir();
  873.     if (!home)
  874.     return;
  875.     
  876.     WMSetFilePanelDirectory(panel, home);
  877. }
  878.  
  879.  
  880. static void 
  881. handleEvents(XEvent *event, void *data)
  882. {
  883.     W_FilePanel *pPtr = (W_FilePanel*)data;
  884.     W_View *view = WMWidgetView(pPtr->win);
  885.  
  886.     if (event->type == ConfigureNotify) {
  887.         if (event->xconfigure.width != view->size.width
  888.             || event->xconfigure.height != view->size.height) {
  889.             unsigned int newWidth = event->xconfigure.width;
  890.             unsigned int newHeight = event->xconfigure.height;
  891.         int newColumnCount;
  892.  
  893.             W_ResizeView(view, newWidth, newHeight);
  894.             WMResizeWidget(pPtr->line, newWidth, 2);
  895.             WMResizeWidget(pPtr->browser, newWidth-14,
  896.                            newHeight-(PHEIGHT-200));
  897.             WMResizeWidget(pPtr->fileField, newWidth-60-10, 24);
  898.             WMMoveWidget(pPtr->nameLabel, 7, newHeight-(PHEIGHT-282));
  899.             WMMoveWidget(pPtr->fileField, 60, newHeight-(PHEIGHT-278));
  900.             WMMoveWidget(pPtr->okButton, newWidth-(PWIDTH-245),
  901.                     newHeight-(PHEIGHT-325));
  902.             WMMoveWidget(pPtr->cancelButton, newWidth-(PWIDTH-165),
  903.                     newHeight-(PHEIGHT-325));
  904.  
  905.             WMMoveWidget(pPtr->trashcanButton, 7, newHeight-(PHEIGHT-325));
  906.             WMMoveWidget(pPtr->createDirButton, 37, newHeight-(PHEIGHT-325));
  907.             WMMoveWidget(pPtr->homeButton, 67, newHeight-(PHEIGHT-325));
  908.             WMMoveWidget(pPtr->disketteButton, 97, newHeight-(PHEIGHT-325));
  909.             WMMoveWidget(pPtr->unmountButton, 127, newHeight-(PHEIGHT-325));
  910.  
  911.         newColumnCount = (newWidth - 14) / 140;
  912.         WMSetBrowserMaxVisibleColumns(pPtr->browser, newColumnCount);
  913.         }
  914.     }
  915. }
  916.  
  917.  
  918. static char*
  919. getCurrentFileName(WMFilePanel *panel)
  920. {
  921.     char *path;
  922.     char *file;
  923.     char *tmp;
  924.     int len;
  925.     
  926.     path = WMGetBrowserPath(panel->browser);
  927.     
  928.     len = strlen(path);
  929.     if (path[len-1]=='/') {
  930.     file = WMGetTextFieldText(panel->fileField);
  931.     tmp = wmalloc(strlen(path)+strlen(file)+8);
  932.         if (file[0]!='/') {
  933.            strcpy(tmp, path);
  934.            strcat(tmp, file);
  935.         } else
  936.            strcpy(tmp, file);
  937.  
  938.     wfree(file);
  939.     wfree(path);
  940.     return tmp;
  941.     } else {
  942.     return path;
  943.     }
  944. }
  945.  
  946.  
  947.  
  948. static Bool
  949. validOpenFile(WMFilePanel *panel)
  950. {
  951.     WMListItem *item;
  952.     int col, haveFile = 0;
  953.     char *file = WMGetTextFieldText(panel->fileField);
  954.  
  955.     if (file[0] != '\0')
  956.         haveFile = 1;
  957.     wfree(file);
  958.  
  959.     col = WMGetBrowserSelectedColumn(panel->browser);
  960.     item = WMGetBrowserSelectedItemInColumn(panel->browser, col);
  961.     if (item) {
  962.     if (item->isBranch && !panel->flags.canChooseDirectories && !haveFile)
  963.         return False;
  964.     else if (!item->isBranch && !panel->flags.canChooseFiles)
  965.             return False;
  966.         else
  967.             return True;
  968.     } else {
  969.         /* we compute for / here */
  970.     if (!panel->flags.canChooseDirectories && !haveFile)
  971.         return False;
  972.         else
  973.             return True;
  974.     }
  975.     return True;
  976. }
  977.  
  978.  
  979.  
  980. static void
  981. buttonClick(WMButton *bPtr, WMFilePanel *panel)
  982. {
  983.     WMRange range;
  984.  
  985.     if (bPtr == panel->okButton) {
  986.         if (!validOpenFile(panel))
  987.             return;
  988.     if (panel->flags.fileMustExist) {
  989.         char *file;
  990.         
  991.         file = getCurrentFileName(panel);
  992.         if (access(file, F_OK)!=0) {
  993.         WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
  994.                 "Error", "File does not exist.",
  995.                 "Ok", NULL, NULL);
  996.         wfree(file);
  997.         return;
  998.         }
  999.         wfree(file);
  1000.     }
  1001.     panel->flags.canceled = 0;
  1002.     } else
  1003.     panel->flags.canceled = 1;
  1004.  
  1005.     range.count = range.position = 0;
  1006.     WMSelectTextFieldRange(panel->fileField, range);
  1007.     panel->flags.done = 1;
  1008. }
  1009.  
  1010.  
  1011.